#****************************************************************************
#* Copyright (c) 2024, Fougue Ltd. <https://www.fougue.pro>
#* All rights reserved.
#* See license at https://github.com/fougue/jyzk/blob/master/LICENSE.txt
#****************************************************************************

cmake_minimum_required(VERSION 3.10)

set(Jyzk_VersionMajor 0)
set(Jyzk_VersionMinor 9)
set(Jyzk_VersionPatch 0)
set(Jyzk_Version ${Jyzk_VersionMajor}.${Jyzk_VersionMinor}.${Jyzk_VersionPatch})

project(
    jyzk
    VERSION ${Jyzk_Version}
    DESCRIPTION "Jyzk - Opensource 3D CAD viewer and converter"
    LANGUAGES CXX
)

set(Jyzk_Copyright "Copyright @ 2016-present, Fougue Ltd., All Rights Reserved")
mark_as_advanced(FORCE Jyzk_Copyright)

set(CMAKE_EXECUTE_PROCESS_COMMAND_ECHO STDOUT)

# Find git commit hash and revision number
set(Jyzk_VersionCommit 0)
set(Jyzk_VersionRevNum 0)

find_package(Git)
if(Git_FOUND)
    # Maybe use preferrably add_custom_command() with PRE_BUILD event?
    message(STATUS "GIT_EXECUTABLE=${GIT_EXECUTABLE}")
    execute_process(
        COMMAND ${GIT_EXECUTABLE} rev-parse --short HEAD
        WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
        OUTPUT_VARIABLE Jyzk_VersionCommit
    )
    execute_process(
        COMMAND ${GIT_EXECUTABLE} rev-list --count HEAD
        WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
        OUTPUT_VARIABLE Jyzk_VersionRevNum
    )
    # Fix newline character at the end of Jyzk_VersionCommit and Jyzk_VersionRevNum variables
    string(REGEX REPLACE "\n$" "" Jyzk_VersionCommit "${Jyzk_VersionCommit}")
    string(REGEX REPLACE "\n$" "" Jyzk_VersionRevNum "${Jyzk_VersionRevNum}")
    # execute_process() may have failed, so make sure Jyzk_Version[Commit/RevNum] are not empty strings
    # Note: execute_process() could fail in the typical case where Jyzk source code was extracted
    #       from ZIP archive file(ie not via "git clone")
    if(Jyzk_VersionCommit STREQUAL "")
        set(Jyzk_VersionCommit 0)
    endif()
    if(Jyzk_VersionRevNum STREQUAL "")
        set(Jyzk_VersionRevNum 0)
    endif()
endif()

list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")

# Find bit size of the target machine
math(EXPR Jyzk_TargetArchBitSize "8 * ${CMAKE_SIZEOF_VOID_P}")

##########
# Options
##########

option(Jyzk_BuildTests "Build Jyzk testing suite" OFF)
option(Jyzk_BuildPluginAssimp "Build plugin to import/export mesh files supported by Assimp" OFF)
if(WIN32)
    set(Jyzk_PostBuildCopyRuntimeDLLs_DefaultValue OFF)
    if(CMAKE_GENERATOR MATCHES "Visual Studio")
        set(Jyzk_PostBuildCopyRuntimeDLLs_DefaultValue ON)
    endif()

    message(STATUS "Jyzk_PostBuildCopyRuntimeDLLs_DefaultValue=${Jyzk_PostBuildCopyRuntimeDLLs_DefaultValue}")
    option(
        Jyzk_PostBuildCopyRuntimeDLLs
        "\
Add post build step to copy all runtime DLLs alongside Jyzk executable.\n\
This simplifies running Jyzk from eg Visual Studio IDE\
"
        ${Jyzk_PostBuildCopyRuntimeDLLs_DefaultValue}
    )
endif()

# TODO Make option Jyzk_BuildTests dependent of Jyzk_BuildApp)
option(Jyzk_BuildApp "Build Jyzk GUI application" ON)
option(Jyzk_BuildConvCli "Build Jyzk CLI converter" ON)

# TODO
# option(Jyzk_BuildPluginGmio "Build plugin to import/export mesh files supported by gmio" OFF)

##########
# Qt
##########

find_package(QT NAMES Qt6 Qt5 REQUIRED)
if(QT_FOUND)
    message(STATUS "Qt version ${QT_VERSION}")
    if(QT_VERSION VERSION_LESS 5.14)
        message(FATAL_ERROR "Qt >= 5.14 is required but detected version is ${QT_VERSION}")
    endif()

    set("Qt${QT_VERSION_MAJOR}_DIR" "${QT_DIR}")

    if(Jyzk_BuildApp OR Jyzk_BuildConvCli)
        find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core)
    endif()

    if(Jyzk_BuildApp)
        find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Gui Widgets Test)
        if(WIN32 AND QT_VERSION_MAJOR EQUAL 5)
            find_package(Qt5 REQUIRED COMPONENTS WinExtras)
        elseif(QT_VERSION_MAJOR EQUAL 6)
            find_package(Qt6 REQUIRED COMPONENTS OpenGLWidgets)
        endif()

        if(Jyzk_PostBuildCopyRuntimeDLLs)
            find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Svg)
        endif()
    endif()
endif()

#qt_standard_project_setup()
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTORCC ON)

##########
# Compiler config
##########

set(CMAKE_CXX_STANDARD 17)

set(
    Jyzk_CompileDefinitions
    QT_DISABLE_DEPRECATED_BEFORE=0x050F00
    QT_IMPLICIT_QFILEINFO_CONSTRUCTION
)
set(Jyzk_CompileOptions)

if(MSVC)
    list(APPEND Jyzk_CompileDefinitions NOMINMAX)
    # Deletion of pointer to incomplete type 'XXXX'; no destructor called
    list(APPEND Jyzk_CompileOptions /we4150)
    # Specify both the source character set and the execution character set as UTF-8
    list(APPEND Jyzk_CompileOptions /utf-8)
    if(QT_VERSION_MAJOR EQUAL 6)
        list(APPEND Jyzk_CompileDefinitions _USE_MATH_DEFINES)
    endif()
elseif(APPLE)
    list(APPEND Jyzk_CompileDefinitions GL_SILENCE_DEPRECATION)
endif()

if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
    list(
        APPEND Jyzk_CompileOptions
        -Wno-undefined-var-template
        -Wno-deprecated-declarations
        -Wno-macro-redefined
    )
endif()

if(Jyzk_TargetArchBitSize STREQUAL "32")
    if(APPLE)
        list(APPEND Jyzk_CompileDefinitions _DARWIN_USE_64_BIT_INODE)
    elseif(UNIX)
        list(APPEND Jyzk_CompileDefinitions _FILE_OFFSET_BITS=64  _LARGEFILE64_SOURCE=1)
    endif()

    if(CMAKE_SYSTEM_PROCESSOR MATCHES "arm")
        # See:
        #     https://stackoverflow.com/questions/48149323/what-does-the-gcc-warning-project-parameter-passing-for-x-changed-in-gcc-7-1-m
        #     https://stackoverflow.com/questions/52020305/what-exactly-does-gccs-wpsabi-option-do-what-are-the-implications-of-supressi
        list(APPEND Jyzk_CompileOptions -Wno-psabi)
    endif()
endif()

##########
# Linker config
##########

set(JyzkCore_LinkDirectories)
set(JyzkCore_LinkLibraries)
set(JyzkIO_LinkLibraries)

if(MSVC)
    list(APPEND JyzkCore_LinkLibraries Opengl32 User32)
elseif(APPLE)
    list(APPEND JyzkCore_LinkLibraries iconv)
endif()

##########
# Set "include" directories
##########

set(
    Jyzk_IncludeDirectories
    src/3rdparty
    ${CMAKE_BINARY_DIR}
)

##########
# JyzkCore+JyzkIO source files
##########

file(
    GLOB JyzkCore_SourceFiles
    ${PROJECT_SOURCE_DIR}/src/base/*.cpp
    ${PROJECT_SOURCE_DIR}/src/graphics/*.cpp
    ${PROJECT_SOURCE_DIR}/src/gui/*.cpp
    ${PROJECT_SOURCE_DIR}/src/3rdparty/fmt/src/format.cc
)

file(
    GLOB JyzkIO_SourceFiles
    ${PROJECT_SOURCE_DIR}/src/io_dxf/*.cpp
    ${PROJECT_SOURCE_DIR}/src/io_image/*.cpp
    ${PROJECT_SOURCE_DIR}/src/io_occ/*.cpp
    ${PROJECT_SOURCE_DIR}/src/io_off/*.cpp
    ${PROJECT_SOURCE_DIR}/src/io_ply/*.cpp
)

##########
# JyzkCore+JyzkIO header files
##########

file(
    GLOB JyzkCore_HeaderFiles
    ${PROJECT_SOURCE_DIR}/src/base/*.h
    ${PROJECT_SOURCE_DIR}/src/graphics/*.h
    ${PROJECT_SOURCE_DIR}/src/gui/*.h
)

file(
    GLOB JyzkIO_HeaderFiles
    ${PROJECT_SOURCE_DIR}/src/io_dxf/*.h
    ${PROJECT_SOURCE_DIR}/src/io_image/*.h
    ${PROJECT_SOURCE_DIR}/src/io_occ/*.h
    ${PROJECT_SOURCE_DIR}/src/io_off/*.h
    ${PROJECT_SOURCE_DIR}/src/io_ply/*.h
)

##########
# Unit tests
##########

if(Jyzk_BuildTests)
    file(GLOB JyzkTests_HeaderFiles ${PROJECT_SOURCE_DIR}/tests/*.h)
    file(GLOB JyzkTests_SourceFiles ${PROJECT_SOURCE_DIR}/tests/*.cpp)

    set(JYZK_WITH_TESTS 1)
    list(APPEND JyzkTests_LinkLibraries Qt${QT_VERSION_MAJOR}::Test)

    file(GLOB JyzkTests_InputFiles ${PROJECT_SOURCE_DIR}/tests/inputs/*.*)
    file(COPY ${JyzkTests_InputFiles} DESTINATION ${CMAKE_BINARY_DIR}/tests/inputs)
    file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/tests/outputs)
endif()

##########
# OpenCascade
##########
unset(WIN32)
if(WIN32)
    # Can't use find_package(OpenCASCADE) as OpenCASCADEConfig.cmake is broken for Windows platform
    # See https://dev.opencascade.org/content/3rdparty-hard-coded-paths-when-building-against-opencascade
    include(${PROJECT_SOURCE_DIR}/cmake/OpenCascadeWin.cmake)
    if (OpenCASCADE_FOUND)
        # Add OpenCASCADE include directory
        list(APPEND Jyzk_IncludeDirectories ${OpenCASCADE_INCLUDE_DIR})

        # Add OpenCASCADE library directories
        # Note: QtCreator option "Run->Add build library search to PATH" will add to PATH env variable
        #       the contents of JyzkCore_LinkDirectories variable. For convenience, let's add also the
        #       directories containing DLLs
        list(
            APPEND JyzkCore_LinkDirectories
            ${OpenCASCADE_BINARY_DIR}
            ${OpenCASCADE_LIBRARY_DIR}
            ${OpenCASCADE_3RDPARTY_BINARY_DIRS}
        )    
    else()
        message(STATUS "OpenCascade Not Found")
    endif()
else()
    set(OpenCASCADE_WANT "D:/SoftWare/Library/OCCT/occt-vc143-64")
    set(CMAKE_PREFIX_PATH
        ${OpenCASCADE_WANT}/cmake/cmake
    )
    find_package(OpenCASCADE REQUIRED)
    if(OpenCASCADE_FOUND)
        # It seems that OpenCascade cmake package files specify INTERFACE_INCLUDE_DIRECTORIES
        # starting from 7.7.0 version only
        # Older versions require to explicitly add OpenCascade include dir
        get_target_property(OpenCASCADE_TKernel_INCLUDE_DIR TKernel INTERFACE_INCLUDE_DIRECTORIES)
        list(FIND OpenCASCADE_TKernel_INCLUDE_DIR ${OpenCASCADE_INCLUDE_DIR} OpenCASCADE_TKernel_INCLUDE_DIR_IsSet)
        if(OpenCASCADE_TKernel_INCLUDE_DIR_IsSet EQUAL -1)
            list(APPEND Jyzk_IncludeDirectories ${OpenCASCADE_INCLUDE_DIR})
        endif()
    endif()
endif()
set(WIN32)

list(APPEND Jyzk_CompileDefinitions OCCT_HANDLE_NOCAST)
if(UNIX AND NOT APPLE)
    list(APPEND Jyzk_CompileDefinitions OCC_CONVERT_SIGNALS)
endif()

if(OpenCASCADE_FOUND)
    message(STATUS "OpenCascade version ${OpenCASCADE_VERSION}")

    # std::iterator class template(used as a base class to provide typedefs) is deprecated in C++17
    # OpenCascade < 7.7.0 uses std::iterator for NCollection_StlIterator and this is causing many
    # deprecation warnings
    if(OpenCASCADE_VERSION VERSION_LESS 7.7.0)
        if(MSVC)
            # Silent warnings C4996 and STL4015
            list(APPEND Jyzk_CompileDefinitions _SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING)
        elseif((CMAKE_CXX_COMPILER_ID MATCHES "GNU") AND (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 12))
            list(APPEND Jyzk_CompileOptions -Wno-deprecated-declarations)
        endif()
    endif()

    # Add OpenCASCADE libraries
    list(
        APPEND JyzkCore_LinkLibraries
        # FoundationClasses
        TKernel TKMath
        # ModelingData
        TKG2d TKG3d TKGeomBase TKBRep
        # ModelingAlgorithms
        TKBO TKBool TKGeomAlgo TKHLR TKMesh TKPrim TKShHealing TKTopAlgo
        # Visualization
        TKMeshVS TKOpenGl TKService TKV3d
        # ApplicationFramework
        TKBin TKBinL TKBinXCAF TKCAF TKCDF TKLCAF TKVCAF TKXml TKXmlL
        # DataExchange
        TKXCAF TKXmlXCAF TKXSBase
    )

    if(OpenCASCADE_VERSION VERSION_GREATER_EQUAL 7.8.0)
        list(APPEND JyzkIO_LinkLibraries TKDE)
        list(APPEND JyzkIO_LinkLibraries TKDEIGES)
        list(APPEND JyzkIO_LinkLibraries TKDESTEP)
        list(APPEND JyzkIO_LinkLibraries TKDESTL)
        list(APPEND JyzkIO_LinkLibraries TKDEVRML)
    else()
        list(APPEND JyzkIO_LinkLibraries TKIGES TKXDEIGES)
        list(APPEND JyzkIO_LinkLibraries TKSTEP TKSTEP209 TKSTEPAttr TKSTEPBase TKXDESTEP)
        list(APPEND JyzkIO_LinkLibraries TKSTL)
        list(APPEND JyzkIO_LinkLibraries TKVRML)
        if(OpenCASCADE_VERSION VERSION_GREATER_EQUAL 7.7.0)
            list(APPEND JyzkIO_LinkLibraries TKXDE)
        endif()
    endif()

    # OBJ/glTF support
    if(OpenCASCADE_VERSION VERSION_GREATER_EQUAL 7.4.0)
        list(APPEND JyzkIO_LinkLibraries TKRWMesh)
        if(OpenCASCADE_VERSION VERSION_GREATER_EQUAL 7.8.0)
            list(APPEND JyzkIO_LinkLibraries TKDEOBJ TKDEGLTF)
        endif()
    else()
        list(
            REMOVE_ITEM JyzkIO_SourceFiles
            ${PROJECT_SOURCE_DIR}/src/io_occ/io_occ_base_mesh.cpp
            ${PROJECT_SOURCE_DIR}/src/io_occ/io_occ_gltf_reader.cpp
            ${PROJECT_SOURCE_DIR}/src/io_occ/io_occ_obj_reader.cpp
        )
        message(STATUS "glTF reader disabled because OpenCascade < v7.4")
        message(STATUS "OBJ reader disabled because OpenCascade < v7.4")
    endif()

    if(OpenCASCADE_VERSION VERSION_LESS 7.5.0)
        list(REMOVE_ITEM JyzkIO_SourceFiles ${PROJECT_SOURCE_DIR}/src/io_occ/io_occ_gltf_writer.cpp)
        message(STATUS "glTF writer disabled because OpenCascade < v7.5")
    endif()

    if(OpenCASCADE_VERSION VERSION_LESS 7.6.0)
        list(REMOVE_ITEM JyzkIO_SourceFiles ${PROJECT_SOURCE_DIR}/src/io_occ/io_occ_obj_writer.cpp)
        message(STATUS "OBJ writer disabled because OpenCascade < v7.6")
    endif()

    # VRML support
    if(OpenCASCADE_VERSION VERSION_LESS 7.7.0)
        list(REMOVE_ITEM JyzkIO_SourceFiles ${PROJECT_SOURCE_DIR}/src/io_occ/io_occ_vrml_reader.cpp)
        message(STATUS "VRML reader disabled because OpenCascade < v7.7")
    endif()
endif()

##########
# Assimp plugin
##########

if(Jyzk_BuildPluginAssimp)
    if(OpenCASCADE_VERSION VERSION_GREATER_EQUAL 7.5.0)
        find_package(assimp)
        if(NOT assimp_FOUND)
            message(WARNING "Assimp library not found")
        endif()
    else()
        message(STATUS "Assimp reader disabled because OpenCascade < v7.5")
    endif()
endif()

if(assimp_FOUND)
    message(STATUS "assimp version ${assimp_VERSION}")
    set(JYZK_HAVE_ASSIMP 1)

    file(GLOB JyzkPluginAssimp_HeaderFiles ${PROJECT_SOURCE_DIR}/src/io_assimp/*.h)
    file(GLOB JyzkPluginAssimp_SourceFiles ${PROJECT_SOURCE_DIR}/src/io_assimp/*.cpp)
    list(APPEND JyzkIO_HeaderFiles ${JyzkPluginAssimp_HeaderFiles})
    list(APPEND JyzkIO_SourceFiles ${JyzkPluginAssimp_SourceFiles})

    list(APPEND JyzkIO_LinkLibraries ${ASSIMP_LIBRARIES})

    list(GET ASSIMP_INCLUDE_DIRS 0 assimp_IncludeDir)
    file(READ "${assimp_IncludeDir}/assimp/version.h" assimp_FileVersionH)
    if(assimp_FileVersionH MATCHES "aiGetVersionPatch")
        set(JYZK_HAVE_ASSIMP_aiGetVersionPatch 1)
    else()
        message(STATUS "Assimp function aiGetVersionPatch() not available")
    endif()
endif()

##########
# gmio
##########

# TODO Finalize
if(gmio_FOUND)
    message(STATUS "gmio version ${gmio_VERSION}")
    set(JYZK_HAVE_GMIO 1)

    file(GLOB JyzkPluginGmio_HeaderFiles ${PROJECT_SOURCE_DIR}/src/io_gmio/*.h)
    file(GLOB JyzkPluginGmio_SourceFiles ${PROJECT_SOURCE_DIR}/src/io_gmio/*.cpp)
    list(APPEND JyzkIO_HeaderFiles ${JyzkPluginGmio_HeaderFiles})
    list(APPEND JyzkIO_SourceFiles ${JyzkPluginGmio_SourceFiles})

    # Needs -L$$GMIO_ROOT/lib -lgmio_static -lzlibstatic
    list(APPEND JyzkIO_LinkLibraries ${GMIO_LIBRARIES})
endif()

##########
# Configure files
##########

configure_file(${PROJECT_SOURCE_DIR}/src/jyzk_config.h.cmake  common/jyzk_config.h  @ONLY)
configure_file(${PROJECT_SOURCE_DIR}/src/jyzk_version.h.cmake common/jyzk_version.h @ONLY)

##########
# Icons for Jyzk exe targets
##########

if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
    set(Jyzk_AppIconMacOS images/appicon.icns)
    set_source_files_properties(images/appicon.icns PROPERTIES MACOSX_PACKAGE_LOCATION "Resources")
endif()

if(MSVC)
    set(Jyzk_RcIconsWin ${PROJECT_SOURCE_DIR}/images/appicon.rc)
endif()

##########
# Target: JyzkCore(static lib)
##########

add_library(JyzkCore STATIC ${JyzkCore_HeaderFiles} ${JyzkCore_SourceFiles})

target_include_directories(JyzkCore PRIVATE ${Jyzk_IncludeDirectories})
target_compile_definitions(JyzkCore PRIVATE ${Jyzk_CompileDefinitions})
target_compile_options(JyzkCore PRIVATE ${Jyzk_CompileOptions})
target_link_libraries(JyzkCore PRIVATE ${JyzkCore_LinkLibraries})

add_library(JyzkCoreLib INTERFACE)
target_link_libraries(JyzkCoreLib INTERFACE JyzkCore ${JyzkCore_LinkLibraries})
target_link_directories(JyzkCoreLib INTERFACE ${JyzkCore_LinkDirectories})
target_include_directories(JyzkCoreLib INTERFACE ${Jyzk_IncludeDirectories})

##########
# Target: JyzkIO(static lib)
##########

add_library(JyzkIO STATIC ${JyzkIO_HeaderFiles} ${JyzkIO_SourceFiles})

target_include_directories(JyzkIO PRIVATE ${Jyzk_IncludeDirectories})
target_compile_definitions(JyzkIO PRIVATE ${Jyzk_CompileDefinitions})
target_compile_options(JyzkIO PRIVATE ${Jyzk_CompileOptions})
target_link_libraries(JyzkIO PRIVATE JyzkCore ${JyzkIO_LinkLibraries})

add_library(JyzkIOLib INTERFACE)
target_link_libraries(JyzkIOLib INTERFACE JyzkIO JyzkCoreLib ${JyzkIO_LinkLibraries})

##########
# Target: JyzkApp
##########

set(JyzkApp_HeaderFiles)
set(JyzkApp_SourceFiles)
set(JyzkApp_LinkLibraries)

# JyzkApp headers
file(
    GLOB JyzkApp_HeaderFiles
    ${PROJECT_SOURCE_DIR}/src/app/*.h
    ${PROJECT_SOURCE_DIR}/src/measure/*.h
    ${PROJECT_SOURCE_DIR}/src/qtbackend/*.h
    ${PROJECT_SOURCE_DIR}/src/qtcommon/*.h
)

if(WIN32 AND QT_VERSION_MAJOR EQUAL 5)
    list(APPEND JyzkApp_HeaderFiles ${PROJECT_SOURCE_DIR}/src/app/windows/win_taskbar_global_progress.h)
endif()

# JyzkApp sources
file(
    GLOB JyzkApp_SourceFiles
    ${PROJECT_SOURCE_DIR}/src/app/*.cpp
    ${PROJECT_SOURCE_DIR}/src/measure/*.cpp
    ${PROJECT_SOURCE_DIR}/src/qtbackend/*.cpp
    ${PROJECT_SOURCE_DIR}/src/qtcommon/*.cpp
)

if(WIN32 AND QT_VERSION_MAJOR EQUAL 5)
    list(APPEND JyzkApp_SourceFiles ${PROJECT_SOURCE_DIR}/src/app/windows/win_taskbar_global_progress.cpp)
endif()

# JyzkApp UI files
file(GLOB JyzkApp_QtUiFiles ${PROJECT_SOURCE_DIR}/src/app/*.ui)

# JyzkApp unit tests
if(Jyzk_BuildTests)
    list(APPEND JyzkApp_HeaderFiles ${JyzkTests_HeaderFiles})
    list(APPEND JyzkApp_SourceFiles ${JyzkTests_SourceFiles})
    list(APPEND JyzkApp_LinkLibraries ${JyzkTests_LinkLibraries})
endif()

# JyzkApp libs
list(
    APPEND JyzkApp_LinkLibraries
    JyzkCoreLib
    JyzkIOLib
    Qt${QT_VERSION_MAJOR}::Core
    Qt${QT_VERSION_MAJOR}::Gui
    Qt${QT_VERSION_MAJOR}::Widgets
)

if(WIN32 AND QT_VERSION_MAJOR EQUAL 5)
    list(APPEND JyzkApp_LinkLibraries Qt5::WinExtras)
elseif(QT_VERSION_MAJOR EQUAL 6)
    list(APPEND JyzkApp_LinkLibraries Qt6::OpenGLWidgets)
endif()

if(Jyzk_PostBuildCopyRuntimeDLLs)
    list(APPEND JyzkApp_LinkLibraries Qt${QT_VERSION_MAJOR}::Svg)
endif()

if(Jyzk_BuildApp)
    add_executable(
        jyzk
        ${JyzkApp_SourceFiles}
        ${JyzkApp_HeaderFiles}
        ${JyzkApp_QtUiFiles}
        i18n/jyzk.qrc
        i18n/qt${QT_VERSION_MAJOR}base.qrc
        images/jyzk.qrc
        ${Jyzk_RcIconsWin}
        ${Jyzk_AppIconMacOS}
    )

    target_compile_definitions(jyzk PRIVATE ${Jyzk_CompileDefinitions})
    target_compile_options(jyzk PRIVATE ${Jyzk_CompileOptions})
    target_link_libraries(jyzk PRIVATE ${JyzkApp_LinkLibraries})
    # Required by generated Qt UI files
    target_include_directories(jyzk PRIVATE ${PROJECT_SOURCE_DIR}/src/app)

    set_target_properties(
        jyzk
        PROPERTIES
            MACOSX_BUNDLE_BUNDLE_NAME "jyzk"
            MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
            MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
            MACOSX_BUNDLE_COPYRIGHT ${Jyzk_Copyright}
            MACOSX_BUNDLE_ICON_FILE appicon.icns
            WIN32_EXECUTABLE TRUE
            MACOSX_BUNDLE TRUE
    )

    if(Jyzk_PostBuildCopyRuntimeDLLs)
        # Copy required Qt plugins
        set(QtPluginsDir "${QT_DIR}/../../../plugins")
        file(GLOB QtPluginIconEnginesDLLs  "${QtPluginsDir}/iconengines/qsvgicon*.dll")
        file(GLOB QtPluginImageFormatsDLLs "${QtPluginsDir}/imageformats/qsvg*.dll")
        file(GLOB QtPluginPlatformsDLLs    "${QtPluginsDir}/platforms/qwindows*.dll")
        set(QtPluginsDLLs ${QtPluginIconEnginesDLLs} ${QtPluginImageFormatsDLLs} ${QtPluginPlatformsDLLs})
        foreach(QtPluginDLL ${QtPluginsDLLs})
            cmake_path(GET QtPluginDLL PARENT_PATH QtPluginDLL_Path)
            cmake_path(GET QtPluginDLL_Path FILENAME QtPluginDLL_PathName)
            add_custom_command(
                TARGET jyzk POST_BUILD
                COMMAND ${CMAKE_COMMAND} -E make_directory "$<TARGET_FILE_DIR:jyzk>/plugins/${QtPluginDLL_PathName}"
            )
            add_custom_command(
                TARGET jyzk POST_BUILD
                COMMAND ${CMAKE_COMMAND} -E copy_if_different
                        "${QtPluginDLL}" "$<TARGET_FILE_DIR:jyzk>/plugins/${QtPluginDLL_PathName}"
            )
        endforeach()

        # Copy OpenCascade 3rd-party DLLs
        foreach(Occ3rdDLL ${OpenCASCADE_3RDPARTY_DLLS})
            add_custom_command(
                TARGET jyzk POST_BUILD
                COMMAND ${CMAKE_COMMAND} -E copy_if_different "${Occ3rdDLL}" $<TARGET_FILE_DIR:jyzk>
            )
        endforeach()

        # Copy runtime DLLs specified with library IMPORTED_LOCATION property
        add_custom_command(
            TARGET jyzk POST_BUILD
            COMMAND ${CMAKE_COMMAND} -E copy_if_different
                    $<TARGET_RUNTIME_DLLS:jyzk> $<TARGET_FILE_DIR:jyzk>
            COMMAND_EXPAND_LISTS
        )
    endif() # Jyzk_PostBuildCopyRuntimeDLLs
endif() # Jyzk_BuildApp

##########
# Target: jyzk-conv
##########

file(
    GLOB JyzkConv_HeaderFiles
    ${PROJECT_SOURCE_DIR}/src/cli/*.h
    ${PROJECT_SOURCE_DIR}/src/qtbackend/*.h
    ${PROJECT_SOURCE_DIR}/src/qtcommon/*.h
)
list(
    APPEND JyzkConv_HeaderFiles
    ${PROJECT_SOURCE_DIR}/src/app/app_module_properties.h
    ${PROJECT_SOURCE_DIR}/src/app/app_module.h
    ${PROJECT_SOURCE_DIR}/src/app/app_ui_state.h
    ${PROJECT_SOURCE_DIR}/src/app/library_info.h
    ${PROJECT_SOURCE_DIR}/src/app/recent_files.h
)

file(
    GLOB JyzkConv_SourceFiles
    ${PROJECT_SOURCE_DIR}/src/cli/*.cpp
    ${PROJECT_SOURCE_DIR}/src/qtbackend/*.cpp
    ${PROJECT_SOURCE_DIR}/src/qtcommon/*.cpp
)
list(
    APPEND JyzkConv_SourceFiles
    ${PROJECT_SOURCE_DIR}/src/app/app_module_properties.cpp
    ${PROJECT_SOURCE_DIR}/src/app/app_module.cpp
    ${PROJECT_SOURCE_DIR}/src/app/app_ui_state.cpp
    ${PROJECT_SOURCE_DIR}/src/app/library_info.cpp
    ${PROJECT_SOURCE_DIR}/src/app/recent_files.cpp
)

if(Jyzk_BuildConvCli)
    add_executable(
        jyzk-conv
        ${JyzkConv_HeaderFiles}
        ${JyzkConv_SourceFiles}
        i18n/jyzk.qrc
        i18n/qt${QT_VERSION_MAJOR}base.qrc
        ${Jyzk_RcIconsWin}
        ${Jyzk_AppIconMacOS}
    )

    target_compile_definitions(jyzk-conv PRIVATE ${Jyzk_CompileDefinitions})
    target_compile_options(jyzk-conv PRIVATE ${Jyzk_CompileOptions})

    target_link_libraries(
        jyzk-conv PRIVATE
        JyzkCoreLib
        JyzkIOLib
        Qt${QT_VERSION_MAJOR}::Core
    )
endif() # Jyzk_BuildConvCli

##########
# Target: OtherFiles
##########

add_custom_target(
    OtherFiles SOURCES
    .github/workflows/ci_linux.yml
    .github/workflows/ci_linux_arm.yml
    .github/workflows/ci_macos.yml
    .github/workflows/ci_macos_conda.yml
    .github/workflows/ci_windows.yml
    images/credits.txt
    scripts/bump-version.rb
    scripts/gen-cmake-opencascade-vars.bat
    src/jyzk_config.h.cmake
    src/jyzk_version.h.cmake
    README.md
)
